package org.springblade.upgrade.nacos;

import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.tool.api.R;
import org.springblade.upgrade.nacos.constant.NacosUtil;
import org.springblade.upgrade.nacos.model.NacosInstanceBean;
import org.springblade.upgrade.nacos.model.NacosInstanceInfo;
import org.springblade.upgrade.nacos.model.NacosServerBean;
import org.springblade.upgrade.nacos.model.NacosToken;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.Collections;

/**
 * 地址
 */
@Slf4j
@Service
public class NacosServer {

    @Resource
    private NacosProperties nacosProperties;

    //基础地址
    private String baseUrl;

    //token
    private NacosToken nacosToken;

    @PostConstruct
    private void init() {
        String address = nacosProperties.getServerAddr();
        if (address == null) {
            address = "";
        }
        address = address.trim();
        while (address.endsWith("\\") || address.endsWith("/")) {
            address = address.substring(0, address.length() - 1);
        }
        while (address.startsWith("\\") || address.startsWith("/")) {
            address = address.substring(1);
        }
        baseUrl = "http://" + address + "/nacos";
    }


    /**
     * 登录服务
     *
     * @return
     */
    public synchronized NacosToken login() throws Exception {
        //清理
        nacosToken = null;
        //地址
        String url = baseUrl + "/v1/auth/users/login";
        // 构造表单参数
        HttpRequest request = HttpRequest.post(url)
                .form("username", nacosProperties.getUsername())
                .form("password", nacosProperties.getPassword());
        request.contentType("application/x-www-form-urlencoded");
        String body = request.execute().body();   // 获取响应主体
        nacosToken = JSONUtil.toBean(body, NacosToken.class);
        if (nacosToken == null) {
            throw new Exception("登录失败");
        }
        return nacosToken;
    }


    /**
     * 服务
     *
     * @return
     */
    private NacosServerBean queryServerListAction() throws Exception {
        //地址
        StringBuilder url = new StringBuilder(baseUrl);
        url.append("/v1/ns/catalog/services?hasIpCount=true&withInstances=false&pageNo=1&pageSize=1000");
        url.append("&namespaceId=").append(nacosProperties.getNamespace());
        url.append("&accessToken=").append(nacosToken.getAccessToken());
        //GET请求
        log.info("地址:" + url.toString());
        HttpRequest request = HttpRequest.get(url.toString());
        String body = request.execute().body();   // 获取响应主体
        log.info("结果:" + body);
        return JSONUtil.toBean(body, NacosServerBean.class);
    }

    /**
     * 服务
     *
     * @return
     */
    public NacosServerBean queryServerList() throws Exception {
        //先登录
        if (nacosToken == null) {
            login();
        }
        NacosServerBean result;
        try {
            result = queryServerListAction();
        } catch (Exception ex) {
            //重新登录
            login();
            //再次执行业务
            result = queryServerListAction();
            if (result == null) {
                result = new NacosServerBean();
            }
        }
        return result;
    }

    /**
     * 实例
     * &serviceName=pub-plat-logistics&namespaceId=ae4e22a3-5039-4aee-9b4d-637b12b9e558
     *
     * @return
     */
    private NacosInstanceBean queryInstancesAction(String serverName) throws Exception {
        //地址
        StringBuilder url = new StringBuilder(baseUrl);
        url.append("/v1/ns/catalog/instances?pageSize=1000&pageNo=1&clusterName=DEFAULT&groupName=DEFAULT_GROUP");
        url.append("&namespaceId=").append(nacosProperties.getNamespace());
        url.append("&serviceName=").append(serverName);
        url.append("&accessToken=").append(nacosToken.getAccessToken());
        //GET请求
        log.info("地址:" + url.toString());
        HttpRequest request = HttpRequest.get(url.toString());
        String body = request.execute().body();   // 获取响应主体
        log.info("结果:" + body);
        try {
            return JSONUtil.toBean(body, NacosInstanceBean.class);
        } catch (Exception ex) {
            log.error("" + ex.getMessage(), ex);
            NacosInstanceBean a = new NacosInstanceBean();
            a.setCount(0);
            a.setList(Collections.emptyList());
            return a;
        }

    }

    /**
     * 实例
     *
     * @return
     */
    public NacosInstanceBean queryInstances(String serverName) throws Exception {
        //先登录
        if (nacosToken == null) {
            login();
        }
        NacosInstanceBean result;
        try {
            result = queryInstancesAction(serverName);
        } catch (Exception ex) {
            //重新登录
            login();
            //再次执行业务
            result = queryInstancesAction(serverName);
            if (result == null) {
                result = new NacosInstanceBean();
            }
        }
        //转换
        NacosUtil.convert(result);
        return result;
    }

    /**
     * 更新上下线
     *
     * @return
     */
    private R<String> updateEnableAction(NacosInstanceInfo cond, boolean enable) throws Exception {
        //取得实例列表
        NacosInstanceBean instanceBean = queryInstances(cond.getServiceName());
        if (instanceBean == null || instanceBean.getList() == null || instanceBean.getList().isEmpty()) {
            return R.fail("没有查询到实例列表，异常情况，请等待一会后重试！");
        }
        //查找实例列表
        NacosInstanceInfo info = null;
        for (NacosInstanceInfo temp : instanceBean.getList()) {
            if (temp.getIp().equals(cond.getIp()) && temp.getPort().equals(cond.getPort())) {
                info = temp;
                break;
            }
        }
        if (info == null) {
            return R.fail("没有找到实例，异常情况，请等待一会后重试！");
        }
        //设置状态
        info.setEnabled(enable);
        //GET请求
        HttpRequest request = HttpRequest.put(baseUrl + "/v1/ns/instance?accessToken=" + nacosToken.getAccessToken());
        log.info("updateEnableAction 地址:" + baseUrl + "/v1/ns/instance?accessToken=" + nacosToken.getAccessToken());
        request.form("serviceName", cond.getServiceName());
        request.form("ip", cond.getIp());
        request.form("port", cond.getPort());

        request.form("namespaceId", nacosProperties.getNamespace());
        request.form("groupName", nacosProperties.getGroup());

        request.form("clusterName", info.getClusterName());
        request.form("ephemeral", info.getEphemeral());
        request.form("weight", info.getWeight());
        request.form("enabled", info.getEnabled());
        //这个特殊不传可以，测试
//        request.form("metadata",info.getMetadata());
        log.info("updateEnableAction  from:\n{}", JSONUtil.toJsonStr(request.form()));
        //头部
        request.header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36");
        request.header("Cache-Control", "no-cache");
        request.header("Accept", "*/*");
        request.header("Accept-Encoding", "gzip, deflate");
        request.header("Connection", "keep-alive");
        request.header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        //表体
        log.info("updateEnableAction  header:\n{}", JSONUtil.toJsonStr(request.headers()));
        String body = request.execute().body();   // 获取响应主体
        log.info("updateEnableAction 结果:" + body);
        return R.data(body);
    }

    /**
     * 更新上下线
     *
     * @return
     */
    public R<String> updateEnable(NacosInstanceInfo cond, boolean enable) throws Exception {
        if (cond.getServiceName() == null || cond.getServiceName().isEmpty()) {
            return R.fail("服务参数不能为空！");
        }
        if (cond.getIp() == null || cond.getIp().isEmpty()) {
            return R.fail("服务参数不能为空！");
        }
        if (cond.getPort() == null || cond.getPort().isEmpty()) {
            return R.fail("服务端口不能为空！");
        }
        NacosInstanceBean result;
        try {
            return updateEnableAction(cond, enable);
        } catch (Exception ex) {
            ex.printStackTrace();
            return R.fail(ex.getMessage());
        }
    }
}
